<template>
  <div class="calendar">
    <!-- 顶部日期切换栏 -->
    <div class="calendar-tools">
        <div class="calendar-info" @click.stop="changeYear">
          <div class="calendar-title">打卡日历</div>
          <div class="calendar-center">
            <div class="calendar-prev" @click="prev">
              <svg width="20" height="20" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
              <g class="transform-group">
                <g transform="scale(0.015625, 0.015625)">
                    <path style="fill:#fff!important" d="M671.968 912c-12.288 0-24.576-4.672-33.952-14.048L286.048 545.984c-18.752-18.72-18.752-49.12 0-67.872l351.968-352c18.752-18.752 49.12-18.752 67.872 0 18.752 18.72 18.752 49.12 0 67.872l-318.016 318.048 318.016 318.016c18.752 18.752 18.752 49.12 0 67.872C696.544 907.328 684.256 912 671.968 912z" fill="#5e7a88"></path>
                </g>
              </g>
              </svg>
            </div>
            
            <div class="year">{{year}}年</div>
            <div class="month">
              {{month+1}}月
            </div>
            
            <div class="calendar-next"  @click="next">
              <svg width="20" height="20" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
              <g class="transform-group">
                <g transform="scale(0.015625, 0.015625)">
                  <path style="fill:#fff!important" d="M761.056 532.128c0.512-0.992 1.344-1.824 1.792-2.848 8.8-18.304 5.92-40.704-9.664-55.424L399.936 139.744c-19.264-18.208-49.632-17.344-67.872 1.888-18.208 19.264-17.376 49.632 1.888 67.872l316.96 299.84-315.712 304.288c-19.072 18.4-19.648 48.768-1.248 67.872 9.408 9.792 21.984 14.688 34.56 14.688 12 0 24-4.48 33.312-13.44l350.048-337.376c0.672-0.672 0.928-1.6 1.6-2.304 0.512-0.48 1.056-0.832 1.568-1.344C757.76 538.88 759.2 535.392 761.056 532.128z" fill="#5e7a88"></path>
                </g>
              </g>
              </svg>
            </div>
          </div>
          <div class="calendar-reset" @click.stop="setToday">重置</div>
        </div>
        
        <!-- 年份选择 -->
        <div class="calendar-years" v-if="yearsShow" :class="{'show':yearsShow}">
          <span v-for="(y,k3) in years" @click.stop="selectYear(y)" :key="k3" :class="{'active':y==year}">{{y}}</span>
        </div> 
    </div>
    <!-- 星期几 -->
    <table cellpadding="5">
      <thead>
        <!-- 第一行：周一至周日 -->
        <tr>
          <td v-for="(week,k0) in weeks" class="week" :key="k0">{{week}}</td>
        </tr>
      </thead>
      <tbody>
        <!-- 遍历日期 -->
        <tr v-for="(day,k1) in days" :style="{'animation-delay':(k1*30)+'ms'}" :key="k1">
          <td v-for="(child,k2) in day" :class="{'selected':child.selected, 'ranged':child.ranged, 'disabled':child.disabled}" @click="select(k1,k2,$event,child)" :key="k2">
            <div :class="{
              'highlighted':(k1 == selectedRow1 && selectedL1 <= k2 && k2 <= selectedR1 ) || (k1 == selectedRow2 && selectedL2 <= k2 && k2 <= selectedR2) || (k1 > selectedRow1 && k1 < selectedRow2), 
              'left-point':(k1 == selectedRow1 && k2 == selectedL1) || (k1 == selectedRow2 && k2 == selectedL2) || (k1 > selectedRow1 && k1 < selectedRow2 && k2 == 0), 
              'right-point':(k1 == selectedRow1 && k2 == selectedR1) || (k1 == selectedRow2 && k2 == selectedR2) || (k1 > selectedRow1 && k1 < selectedRow2 && k2 == 6)
            }" class="calendar-cell" style="position:relative">
              <span style="position:absolute;width:14px;height:14px;right:3px;bottom:0px;color:rgb(72, 255, 72);" v-if="list.includes(String(child.day))">
                <i class="el-icon-check"></i>
              </span>
              <span>{{child.day}}</span>
            </div>
          </td>
        </tr>
      </tbody>
    </table>

    <!-- <div style="color:#fff;">
      <span>月份：{{month+1}}</span>
      <span>起始点：{{selectedRow1}} - {{selectedL1}} - {{selectedR1}}</span>
      <span>终点：{{selectedRow2}} - {{selectedL2}} - {{selectedR2}}</span>
    </div> -->
  </div>
</template>

<script>
export default {
  props: {
    // 默认日期
    value: {
      type: Array,
      default: function () {
        return []
      }
    },
    // 自定义星期名称
    weeks: {
      type: Array,
      default: function () {
        return window.navigator.language.toLowerCase() == 'zh-cn' ? ['日', '一', '二', '三', '四', '五', '六'] : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']
      }
    },
    // 自定义月份
    months: {
      type: Array,
      default: function () {
        return window.navigator.language.toLowerCase() == 'zh-cn' ? ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'] : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
      }
    },
    // 屏蔽的日期
    disabled: {
      type: Array,
      default: function () {
        return []
      }
    },
    // 是否小于10补零
    zero: {
      type: Boolean,
      default: false
    },
    list: {
      type: Array
    }
  },
  data () {
    return {
      years: [],
      yearsShow: false,
      year: 0, // 当前年
      month: 0, // 当前月
      day: 0, // 当前日
      days: [],
      today: [],

      // 高亮行1（0 - 5）
      selectedRow1: undefined,
      // 高亮行1左端点（0 - 6）
      selectedL1: undefined,
      // 高亮行1右端点（0 - 6）
      selectedR1: undefined,
      // 高亮行2（0 - 5）
      selectedRow2: undefined,
      // 高亮行2左端点（0 - 6）
      selectedL2: undefined,
      // 高亮行2右端点（0 - 6）
      selectedR2: undefined,

      // 高亮区（开始2021-10 - 截止2022-12）
      highlightArea: [
        {selectedRow1: 0, selectedL1: 5, selectedR1: 6, selectedRow2: 4, selectedL2: 0, selectedR2: 2}
      ]
    }
  },
  watch: {
    value () {
      this.init()
    },
  },
  mounted () {
    this.init()
  },
  methods: {
    // 初始化
    init () {
      let now = new Date()
      this.year = now.getFullYear()
      this.month = now.getMonth()
      this.day = now.getDate()
      if (this.value.length > 0) { 
        // 如果有默认日期
        this.year = parseInt(this.value[0])
        this.month = parseInt(this.value[1]) - 1
        this.day = parseInt(this.value[2])
        // console.log('获取到默认日期:' + this.year, this.month, this.day)
      }
      this.render(this.year, this.month)
    },
    // 渲染日期
    render (y, m) {
      this.setHighlightArea(y, m)

      let firstDayOfMonth = new Date(y, m, 1).getDay() // 当月第一天是第几天，0，1，2，3，4，5，6
      let lastDateOfMonth = new Date(y, m + 1, 0).getDate() // 当月有多少天
      let lastDayOfLastMonth = new Date(y, m, 0).getDate() // 上一月有多少天
      this.year = y
      let seletSplit = this.value
      let i // 本月号数
      let line = 0 // 行数
      let temp = [] // 最终输出的二维数组
      let nextMonthPushDays = 1 // 定义初始值
      for (i = 1; i <= lastDateOfMonth; i++) { // 生成当月的天数
        let day = new Date(y, m, i).getDay() // 返回星期几（0～6）
        let k // 补充的号数
        // 第一行,补充行
        if (day == 0) { // 如果是周天，则第一行为空
          temp[line] = []
        } else if (i == 1) { // 第一天不是周天的第一天,则第一行补充前面上月的天数
          temp[line] = []
          k = lastDayOfLastMonth - firstDayOfMonth + 1
          for (let j = 0; j < firstDayOfMonth; j++) {
            temp[line].push(Object.assign( // 对象合并
              {
                day: k, // 号数
                disabled: true // 不可选择
              }
            ))
            k++
          }
        }

        // 生成本月的日期
        let chk = new Date()
        let chkY = chk.getFullYear()
        let chkM = chk.getMonth()
        // 匹配上次选中的日期
        if (parseInt(seletSplit[0]) == this.year && parseInt(seletSplit[1]) - 1 == this.month && parseInt(seletSplit[2]) == i) {
          let now = new Date()
          let year = now.getFullYear()
          let month = now.getMonth()
          let day = now.getDate()
          // 只赋值高亮当前日期
          if(this.year == parseInt(year) && this.month == parseInt(month) && this.day == parseInt(day)) {
            temp[line].push(Object.assign(
              {day: i, selected: true}
            ))
            this.today = [line, temp[line].length - 1] // 当前坐标
          } else {
            temp[line].push(Object.assign(
              {day: i, selected: false}
            ))
            this.today = [line, temp[line].length - 1] // 当前坐标
          }
        } else if (chkY == this.year && chkM == this.month && i == this.day && this.value == '') { // 没有默认值的时候显示选中今天日期
          temp[line].push(Object.assign(
            {day: i, selected: true}
          ))
          this.today = [line, temp[line].length - 1]
        } else {
          // console.log("设置可选范围",i,lunarYear,lunarMonth,lunarValue,lunarInfo)
          let options = Object.assign(
            {
              day: i, // 号数
              selected: false // 是否已选中
            }
          )
          // 如果属于屏蔽的日期，则无法选中
          if (this.disabled.length > 0) {
            if (this.disabled.filter(v => { return this.year === v[0] && this.month === v[1] - 1 && i === v[2] }).length > 0) {
              options.disabled = true
            }
          }
          temp[line].push(options) // 加入此行
        }

        // 到周六换行
        if (day == 6 && i < lastDateOfMonth) {
          line++
        } else if (i == lastDateOfMonth) { // 到最后一天，补充灰块
          let k = 1 // 下月从一号开始
          for (let d = day; d < 6; d++) {
            temp[line].push(Object.assign(
              {
                day: k,
                disabled: true
              }
            ))
            k++
          }
          // 下个月除了补充的前几天开始的日期
          nextMonthPushDays = k
        }
      } // end for

      // console.log(this.year+"/"+this.month+"/"+this.day+":"+line)
      // 补充第六行让视觉稳定
      if (line <= 5 && nextMonthPushDays > 0) {
        // console.log({nextMonthPushDays:nextMonthPushDays,line:line})
        for (let i = line + 1; i <= 5; i++) {
          temp[i] = []
          let start = nextMonthPushDays + (i - line - 1) * 7
          for (let d = start; d <= start + 6; d++) {
            temp[i].push(Object.assign(
              {day: d, disabled: true}
            ))
          }
        }
      }
      this.days = temp
    },
    setHighlightArea(y, m) {
      // 重置高亮区域
      this.selectedRow2 = undefined
      this.selectedL2 = undefined
      this.selectedR2 = undefined
      this.selectedRow1 = undefined
      this.selectedL1 = undefined
      this.selectedR1 = undefined
      // if(y == 2021) {
      //   this.setHighlightItem(this.highlightArea[m-9])
      // } else if(y == 2022) {
      //   this.setHighlightItem(this.highlightArea[m+3])
      // }
    },
    setHighlightItem(data) {
      this.selectedRow2 = data.selectedRow2
      this.selectedL2 = data.selectedL2
      this.selectedR2 = data.selectedR2
      this.selectedRow1 = data.selectedRow1
      this.selectedL1 = data.selectedL1
      this.selectedR1 = data.selectedR1
    },
    // 上月
    prev (e) {
      e.stopPropagation()
      if (this.month == 0) {
        this.month = 11
        this.year = parseInt(this.year) - 1
      } else {
        this.month = parseInt(this.month) - 1
      }
      this.render(this.year, this.month)
      this.$emit('selectMonth', this.month + 1, this.year)
      // this.$emit('prev', this.month + 1, this.year)
    },
    //  下月
    next (e) {
      e.stopPropagation()
      if (this.month == 11) {
        this.month = 0
        this.year = parseInt(this.year) + 1
      } else {
        this.month = parseInt(this.month) + 1
      }
      
      this.render(this.year, this.month)

      this.$emit('selectMonth', this.month + 1, this.year)
      // this.$emit('next', this.month + 1, this.year)
    },
    // 选中日期
    select (k1, k2, e, child) {
      if (e != undefined) e.stopPropagation()

      // 设置高亮起始点和终点
      if(this.selectedRow1 == undefined) {
        // 未设置起点
        this.selectedRow1 = k1
        this.selectedL1 = k2
        this.selectedR1 = k2
      } else if (this.selectedRow2 == undefined) {
        // 已设置起点，未设置终点
        this.selectedRow2 = k1
        this.selectedL2 = k2
        this.selectedR2 = k2
        if(this.selectedRow1 == this.selectedRow2) {
          // 在同一行
          if(this.selectedL1 < this.selectedL2) {
            // 同一行顺序
            this.selectedR1 = this.selectedR2
            this.selectedL2 = this.selectedL1
          } else if(this.selectedL1 > this.selectedL2) {
            // 同一行逆序
            let temp1 = this.selectedL1
            this.selectedL1 = this.selectedL2
            this.selectedL2= temp1
            
            let temp2 = this.selectedR1
            this.selectedR1 = this.selectedR2
            this.selectedR2 = temp2

            this.selectedL2 = this.selectedL1
            this.selectedR1 = this.selectedR2
          } else {
            if(this.selectedR1 == this.selectedR2) {
              // 两点一致，则清空
              this.selectedRow2 = undefined
              this.selectedL2 = undefined
              this.selectedR2 = undefined
              
              this.selectedRow1 = undefined
              this.selectedL1 = undefined
              this.selectedR1 = undefined
            }
          }
        }
        if(this.selectedRow2 > this.selectedRow1) {
          // 至少不在一行
          this.selectedR1 = 6
          this.selectedL2 = 0
        }
        if(this.selectedRow2 < this.selectedRow1) {
          // 不在同一行，起止点互换
          let temp1 = this.selectedRow1
          this.selectedRow1 = this.selectedRow2
          this.selectedRow2 = temp1

          let temp2 = this.selectedL1
          this.selectedL1 = this.selectedL2
          this.selectedL2= temp2
          
          let temp3 = this.selectedR1
          this.selectedR1 = this.selectedR2
          this.selectedR2 = temp3

          this.selectedR1 = 6
          this.selectedL2 = 0
        }
      } else {
        // 都已设置，此时清空终点，重设起点
        this.selectedRow2 = undefined
        this.selectedL2 = undefined
        this.selectedR2 = undefined
        
        this.selectedRow1 = k1
        this.selectedL1 = k2
        this.selectedR1 = k2
      }

      let count = 0
      let points = []
      this.days.forEach(v => {
        v.forEach(vv => {
          if(vv.ranged) {
            points.push(vv)
            count++
          }
          if(count == 2) {
            points[0].ranged = false
            points[1].ranged = false
          }
        })
      })
      if(this.selectedRow1 == undefined && this.selectedRow2 == undefined) {
        // 说明两个点一致，被清空
        this.days[k1][k2].ranged = false
      } else {
        this.days[k1][k2].ranged = true
      }

      // 设置当前选中天
      // this.days[k1][k2].selected = true
      // this.day = this.days[k1][k2].day
      // this.today = [k1, k2]
      // let params = {
      //   date: [this.year, this.zero ? this.zeroPad(this.month + 1) : this.month + 1, this.zero ? this.zeroPad(this.days[k1][k2].day) : this.days[k1][k2].day],
      //   text: child
      // }
    },
 
    // 根据当前年份改变年份数组中的年份
    changeYear () {
      if (this.yearsShow) {
        this.yearsShow = false
        return
      }
      this.yearsShow = true
      this.years = []
      for (let i = ~~this.year; i < ~~this.year + 5; i++) {
        this.years.push(i)
      }
    },
    // 选择年份
    selectYear (value) {
      this.yearsShow = false
      this.year = value
      this.render(this.year, this.month)
      this.$emit('selectYear', value)
    },
    // 返回今天
    setToday () {
      // 关闭年份选择
      this.yearsShow = false
      let now = new Date()
      this.year = now.getFullYear()
      this.month = now.getMonth()
      this.day = now.getDate()
      this.render(this.year, this.month)
      // 遍历当前日找到选中
      this.days.forEach(v => {
        let day = v.find(vv => {
          return vv.day == this.day && !vv.disabled
        })
        if (day != undefined) {
          day.selected = true
          let params = {
            date: [this.year, this.zero ? this.zeroPad(this.month + 1) : this.month + 1, this.zero ? this.zeroPad(this.day) : this.day],
            text: day
          }
        }
      })
    },
    // 日期补零
    zeroPad (n) {
      return String(n < 10 ? '0' + n : n)
    }
  }
}
</script>

<style lang="scss" scoped>
.calendar {
  height: 100%;
  width: 100%;
  background: #fff;
  user-select:none;
}

.calendar-tools{
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: relative;
  height:30px;
  background-color: #3d9cfc;
  color: rgba(255, 255, 255, 1);
}
.calendar-prev, .calendar-next {
  height: 30px;
  cursor: pointer;
  color: #fff;
  display: flex;
  align-items: center;
}
.calendar-info{
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 15px;
  width: 100%;
  padding: 0 20px;
  .calendar-center {
    display: flex;
    justify-content: center;
    align-items: center;
    height: 30px;
  }
  .calendar-title {
    font-size: 14px;
    line-height: 30px;
    color: #FFF;
  }
  .calendar-reset {
    font-size: 14px;
    line-height: 30px;
    color: #FFF;
    cursor: pointer;
  }
  .year {
    margin-right: 2px;
    margin-left: 20px;
    cursor: pointer;
  }
  .month {
    margin-right: 20px;
    cursor: pointer;
  }
}
.calendar table {
  clear: both;
  width: 90%;
  border-collapse: collapse;
  margin: 0 auto;
}
.calendar td {
  height: 34px;
  text-align: center;
  vertical-align: middle;
  font-size: 15px;
  position: relative;
  padding: 0;
}
.calendar td.week{
  color: #999;
  pointer-events:none !important;
  cursor: default !important;
}
.calendar td.disabled {
  color:rgba(153,153,153,0.5);
  pointer-events:none !important;
  cursor: default !important;
}
.calendar td.disabled div, .calendar td.disabled span{
  color:rgba(153,153,153,0.5);
}
.calendar td span{
  color: #999;
  font-size: 14px;
}

.calendar td.selected span{
  color: #ffd699;
}
.calendar td.ranged span{
  color: #ffd699;
}
.calendar td .text{
  position: absolute;
  top:30px;
  left:0;
  right:0;
  text-align: center;
  padding:2px;
  font-size:8px;
  color:#999999;
  overflow: hidden;
  text-overflow:ellipsis;
  white-space: nowrap;
}
.calendar thead td {
  text-transform: uppercase;
  height:30px;
  vertical-align: middle;
}
.calendar-button{
  text-align: center;
}
.calendar-button span{
  cursor: pointer;
  display: inline-block;
  min-height: 1em;
  min-width: 5em;
  vertical-align: baseline;
  background:#5e7a88;
  color:#fff;
  margin: 0 .25em 0 0;
  padding: .6em 2em;
  font-size: 1em;
  line-height: 1em;
  text-align: center;
  border-radius: .3em;
}
.calendar-button span.cancel{
  background:#efefef;
  color:#666;
}
.calendar-years{
  position: absolute;
  top: 30px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  height: 30px;
  background:#fff;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  overflow: auto;
  transition:all .5s cubic-bezier(0.075, 0.82, 0.165, 1);
  pointer-events: none;
  transform: translateY(-10px);
  border-left: 1px solid #ddd;
  border-right: 1px solid #ddd;
  border-bottom: 1px solid #ddd;
  border-bottom-left-radius: 6px;
  border-bottom-right-radius: 6px;
  box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.08);
  z-index: 1;
}
.calendar-years.show{
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0px);
}
.calendar-years>span{
  margin: 1px 5px;
  display: inline-block;
  width:60px;
  line-height: 30px;
  border-radius: 20px;
  text-align: center;
  border: 1px solid #fbfbfb;
  color:#999;
}
.calendar-years>span.active{
  color:rgba(24,144,255);
}
.highlighted {
  background-color: #f1f1f1;
}
.left-point {
  border-top-left-radius: 30px;
  border-bottom-left-radius: 30px;
}
.right-point {
  border-top-right-radius: 30px;
  border-bottom-right-radius: 30px;
}
.right-bg {
  position: absolute;
  width: 40px;
  height: 40px;
  left: 18px;
  top: -7px;
}
.calendar-cell {
  position: relative;
  height: 80%;
  display: flex;
  justify-content: center;
  align-items: center;
}
/* 设置滚动条的样式 */
::-webkit-scrollbar {
  width: 0px;
  height: 0px;
}
</style>